package com.flute.framework.configuration;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.apache.commons.io.FileUtils;

import com.flute.framework.LuceneDocumentBuilder;
import com.flute.framework.data.FileIndexData;
import com.flute.framework.data.impl.RawDataFileProvider;
import com.flute.framework.data.mysql.GroupBySQL;
import com.flute.framework.data.mysql.LimitSQL;
import com.flute.framework.data.mysql.MysqlIndexData;
import com.flute.framework.data.mysql.MysqlNewTypeIndexData;
import com.flute.framework.data.mysql.OrderBySQL;
import com.flute.framework.data.mysql.SQL;
import com.flute.framework.data.mysql.SelectSQL;
import com.flute.framework.data.mysql.WhereSQL;
import com.flute.framework.exception.ConfigurationParseException;
import com.flute.framework.index.IndexFolder;
import com.flute.framework.index.LuceneFileIndexCounter;
import com.flute.framework.index.LuceneIndexer;
import com.flute.framework.index.TimerIndexer;
import com.flute.framework.index.fieldbuilder.AbstractFieldBuilder;
import com.flute.framework.index.fieldbuilder.CharSameFieldBuilder;
import com.flute.framework.index.fieldbuilder.FieldFactor;
import com.flute.framework.index.fieldbuilder.FieldsRecordScorer;
import com.flute.framework.index.fieldbuilder.FuzzyPinyinFieldBuilder;
import com.flute.framework.index.fieldbuilder.LuceneMultiScoreFieldBuilder;
import com.flute.framework.index.fieldbuilder.LuceneScoreFieldBuilder;
import com.flute.framework.index.fieldbuilder.PinyinFieldBuilder;
import com.flute.framework.index.fieldbuilder.PinyinHeaderFieldBuilder;
import com.flute.framework.index.fieldbuilder.SameFieldBuilder;
import com.flute.framework.index.fieldbuilder.SplitedFieldBuilder;
import com.flute.framework.index.fieldbuilder.StoreFieldBuilder;
import com.flute.framework.search.CachedSearcher;
import com.flute.framework.search.LuceneSearcher;
import com.flute.framework.search.LuceneSearcherProvider;
import com.flute.framework.search.ProviderInfo;
import com.flute.framework.search.cache.MemcachedHost;
import com.flute.framework.search.cache.MemcachedResultCache;
import com.flute.framework.search.highlight.KeywordMarker;
import com.flute.framework.search.highlight.PinYinRMSpecialMarkStrategy;
import com.flute.framework.search.highlight.PinyinMarkStrategy;
import com.flute.framework.search.highlight.SameMarkStrategy;
import com.flute.framework.search.highlight.SameRemoveSpecialMarkStrategy;
import com.flute.framework.search.highlight.SimpleMark;
import com.flute.framework.search.highlight.SplitedMarkStrategy;
import com.flute.framework.search.result.AbstractResultParser;
import com.flute.framework.search.result.MarkedResultProperty;
import com.flute.framework.search.result.ResultProperty;
import com.flute.framework.search.result.xmlresult.XMLResultParser;
import com.flute.framework.search.sort.SorterInformation;
import com.flute.framework.search.strategy.AbstractSearchStrategy;
import com.flute.framework.search.strategy.CharSameSearchStrategy;
import com.flute.framework.search.strategy.FuzzySearchStrategy;
import com.flute.framework.search.strategy.MissWordSearchStrategy;
import com.flute.framework.search.strategy.PinyinSearchStrategy;
import com.flute.framework.search.strategy.PrefixSearchStrategy;
import com.flute.framework.search.strategy.SameSearchStrategy;
import com.flute.framework.search.strategy.SplitedSearchStrategy;
import com.flute.framework.search.strategy.SuffixSearchStrategy;
import com.flute.framework.spliter.WordSpliter;
import com.flute.framework.stringprocessor.FloatStringProcessor;
import com.flute.framework.stringprocessor.FuzzyPinyinStringProcessor;
import com.flute.framework.stringprocessor.MeanfulSameStringProcessor;
import com.flute.framework.stringprocessor.PinyinHeadersStringProcessor;
import com.flute.framework.stringprocessor.PinyinsStringProcessor;
import com.flute.framework.stringprocessor.ReverseStringProcessor;
import com.flute.framework.stringprocessor.SameStringProcessor;
import com.flute.framework.stringprocessor.SplitStringProcessor;
import com.flute.framework.stringprocessor.SplitedFuzzyPinyinStringProcessor;
import com.flute.framework.stringprocessor.SplitedPinyinHeadersStringProcessor;
import com.flute.framework.stringprocessor.SplitedPinyinsStringProcessor;
import com.flute.framework.stringprocessor.StandardStringProcessor;
import com.flute.tools.data.mysql.ConnectionInformation;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class FluteXMLConverter {

	public static FluteInformation fluteInformationFromFile(String path)
			throws ConfigurationParseException {
		XStream xs = new XStream(new DomDriver());
		fluteInformationXStream(xs);

		try {
			return (FluteInformation) xs.fromXML(FileUtils.openInputStream(new File(
					path)));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return null;
	}

	public static String fluteInformationToXML(FluteInformation info) {
		XStream xs = new XStream(new DomDriver());
		fluteInformationXStream(xs);

		return xs.toXML(info);
	}

	public static void indexDataXStream(XStream xs) {
		xs.alias("file-index-data", FileIndexData.class);
		xs.aliasAttribute(FileIndexData.class, "location", "location");
		xs.aliasField("snapshop-days", FileIndexData.class, "day");
		xs.aliasField("data-provider", FileIndexData.class, "dataProvider");
		xs.aliasAttribute(RawDataFileProvider.class, "path", "path");

		xs.aliasField("data-parser", FileIndexData.class, "parser");
	}

	public static void mysqlDataXStream(XStream xs) {
		xs.alias("mysql-new-type-index-data", MysqlNewTypeIndexData.class);
		xs.aliasAttribute(MysqlNewTypeIndexData.class, "tableName",
				"table-name");
		xs.aliasField("mysql-connection", MysqlNewTypeIndexData.class,
				"connectionInformation");

		xs.alias("mysql-index-data", MysqlIndexData.class);
		xs.aliasAttribute(MysqlIndexData.class, "tableName", "table-name");
		xs.aliasAttribute(MysqlIndexData.class, "snapshotDate", "snapshot-day");
		xs.aliasField("mysql-connection", MysqlIndexData.class,
				"connectionInformation");

		xs.aliasField("group-by", SQL.class, "groupBy");
		xs.aliasField("order-by", SQL.class, "orderBy");
		xs.alias("sql", SQL.class);
		xs.alias("select", SelectSQL.class);
		xs.alias("where", WhereSQL.class);
		xs.alias("group-by", GroupBySQL.class);
		xs.alias("order-by", OrderBySQL.class);
		xs.alias("limit", LimitSQL.class);

		xs.aliasAttribute(SelectSQL.class, "selectClause", "select-clause");
		xs.aliasAttribute(LimitSQL.class, "limitClause", "limit-clause");
		xs.aliasField("where-clauses", WhereSQL.class, "whereClauses");
		xs.aliasField("group-by-clauses", GroupBySQL.class, "groupByClauses");
		xs.aliasField("order-by-clauses", OrderBySQL.class, "orderByClauses");

		connectionInformationXStream(xs);
	}

	public static void connectionInformationXStream(XStream xs) {
		xs.alias("mysql-connection", ConnectionInformation.class);
		xs.aliasField("db-name", ConnectionInformation.class, "dbName");
		xs.aliasField("user-name", ConnectionInformation.class, "userName");
	}

	public static void fluteInformationXStream(XStream xs) {
		xs.alias("flute", FluteInformation.class);
		xs.aliasAttribute(FluteInformation.class, "name", "name");

		xs.aliasField("timer-indexer", FluteInformation.class, "timerIndexer");
		luceneIndexerXStream(xs);

		xs.aliasField("searchers", FluteInformation.class, "searcherList");
		cacheSearcherXStream(xs);

		xs.aliasField("searcher-provider", FluteInformation.class, "provider");

		stringProcessorXStream(xs);
	}

	public static void luceneIndexerXStream(XStream xs) {
		xs.alias("timer-indexer", TimerIndexer.class);
		xs.aliasAttribute(TimerIndexer.class, "updateInterval",
				"update-interval");
		xs.aliasField("indexer", TimerIndexer.class, "indexer");

		xs.alias("lucene-index", LuceneIndexer.class);
		xs.aliasAttribute(LuceneIndexer.class, "indexerName", "name");
		xs.aliasField("index-folder", LuceneIndexer.class, "folder");
		xs.aliasAttribute(IndexFolder.class, "backupLocation",
				"backup-location");
		xs.aliasAttribute(IndexFolder.class, "backup", "backup");
		xs.aliasAttribute(IndexFolder.class, "location", "path");

		xs.alias("lucene-counter", LuceneFileIndexCounter.class);

		xs.alias("same-field", SameFieldBuilder.class);
		xs.alias("store-field", StoreFieldBuilder.class);

		xs.alias("score-field", LuceneScoreFieldBuilder.class);
		xs.alias("multi-score-field", LuceneMultiScoreFieldBuilder.class);
		xs.aliasField("data-fields", LuceneMultiScoreFieldBuilder.class,
				"dataFields");
		xs.alias("char-same-field", CharSameFieldBuilder.class);
		xs.alias("fuzzy-pinyin-field", FuzzyPinyinFieldBuilder.class);
		xs.alias("pinyin-field", PinyinFieldBuilder.class);
		xs.alias("pinyin-head-field", PinyinHeaderFieldBuilder.class);
		xs.alias("splited-field", SplitedFieldBuilder.class);

		xs.aliasAttribute(AbstractFieldBuilder.class, "docField", "doc-field");
		xs
				.aliasAttribute(AbstractFieldBuilder.class, "dataField",
						"data-field");
		xs.alias("pinyin-field", PinyinFieldBuilder.class);

		xs.aliasField("index-data", LuceneIndexer.class, "data");
		indexDataXStream(xs);
		documentBuilderXStream(xs);
		mysqlDataXStream(xs);
	}

	public static void documentBuilderXStream(XStream xs) {
		xs.aliasField("document-builder", LuceneIndexer.class, "builder");
		xs.alias("lucene-document", LuceneDocumentBuilder.class);
		xs.aliasField("field-builders", LuceneDocumentBuilder.class,
				"fieldBuilderList");

		xs.aliasField("sorters", LuceneDocumentBuilder.class, "sorters");

		xs.alias("fields-scorer", FieldsRecordScorer.class);
		xs.aliasAttribute(FieldsRecordScorer.class, "name", "name");
		xs.aliasField("factors", FieldsRecordScorer.class, "factors");

		xs.alias("factor", FieldFactor.class);
		xs.aliasAttribute(FieldFactor.class, "fieldName", "field-name");
		xs.aliasAttribute(FieldFactor.class, "priority", "priority");
	}

	public static void stringProcessorXStream(XStream xs) {
		xs.alias("same-string", SameStringProcessor.class);
		xs.alias("split-string", SplitStringProcessor.class);
		xs.alias("float-string", FloatStringProcessor.class);
		xs.alias("char-same-string", MeanfulSameStringProcessor.class);
		xs.alias("header-string", PinyinHeadersStringProcessor.class);
		xs.alias("pinyin-string", PinyinsStringProcessor.class);
		xs.alias("reverse-string", ReverseStringProcessor.class);
		xs.alias("standard-string", StandardStringProcessor.class);
		xs.alias("split-pinyin-string", SplitedPinyinsStringProcessor.class);
		xs.alias("split-header-string",
				SplitedPinyinHeadersStringProcessor.class);
		xs.alias("fuzzy-pinyin-string", FuzzyPinyinStringProcessor.class);
		xs.alias("split-fuzzy-pinyin-string",
				SplitedFuzzyPinyinStringProcessor.class);
	}

	public static void luceneSearcherXStream(XStream xs) {
		xs.alias("lucene-searcher", LuceneSearcher.class);
		xs.aliasAttribute(LuceneSearcher.class, "searchName", "name");

		xs.aliasField("searcher-information", LuceneSearcher.class, "info");
		searchInformationXStream(xs);

		xs.aliasField("searcher-provider", LuceneSearcherProvider.class,
				"provider");
		luceneProviderXStream(xs);
	}

	private static void cacheSearcherXStream(XStream xs) {
		xs.alias("cache-searcher", CachedSearcher.class);
		xs.aliasField("searcher", CachedSearcher.class, "searcher");
		xs.aliasField("cache", MemcachedResultCache.class, "cache");

		xs.aliasField("hosts", MemcachedResultCache.class, "hosts");
		xs.aliasAttribute(MemcachedResultCache.class, "timeOut", "timeout");
		xs.alias("host", MemcachedHost.class);
		xs.aliasAttribute(MemcachedHost.class, "host", "host");
		xs.aliasAttribute(MemcachedHost.class, "port", "port");

		luceneSearcherXStream(xs);
	}

	public static void luceneProviderXStream(XStream xs) {

		xs.aliasAttribute(LuceneSearcherProvider.class, "updateInterval",
				"update-interval");
		xs.aliasField("provider-info", LuceneSearcherProvider.class,
				"providerInfo");

		xs.alias("provider-info", ProviderInfo.class);
		xs.aliasAttribute(ProviderInfo.class, "location", "searcher-location");
		xs
				.aliasAttribute(ProviderInfo.class, "indexLocation",
						"index-location");
		xs.aliasAttribute(ProviderInfo.class, "ramDirectory", "isRAM");
		xs.aliasAttribute(ProviderInfo.class, "type", "type");
		xs.aliasAttribute(ProviderInfo.class, "server", "server");
		xs.aliasAttribute(ProviderInfo.class, "port", "port");
		xs.aliasAttribute(ProviderInfo.class, "username", "username");
		xs.aliasAttribute(ProviderInfo.class, "password", "password");
		xs.aliasAttribute(ProviderInfo.class, "workspace", "workspace");
		xs.aliasAttribute(ProviderInfo.class, "charset", "charset");
		xs.aliasAttribute(ProviderInfo.class, "filetype", "filetype");
	}

	public static void searchInformationXStream(XStream xs) {
		xs.alias("searcher-information", SearchInformation.class);
		xs.aliasField("strategies", SearchInformation.class, "strategyList");
		xs.aliasField("sorter-names", SearchInformation.class, "sorterList");
		xs.aliasField("result-parser", SearchInformation.class, "parser");

		sorterInformationXStream(xs);
		searchStrategyXStream(xs);
		resultParserXStream(xs);
	}

	public static void resultParserXStream(XStream xs) {
		xs.alias("result-parser", AbstractResultParser.class);

		xs.alias("xml-parser", XMLResultParser.class);
		xs.aliasAttribute(XMLResultParser.class, "beanPath", "record-path");

		xs.aliasField("total-properties", AbstractResultParser.class,
				"resultProperties");
		xs.aliasField("record-properties", AbstractResultParser.class,
				"markedProperties");

		xs.alias("total-property", ResultProperty.class);
		xs.aliasAttribute(ResultProperty.class, "name", "name");
		xs.aliasAttribute(ResultProperty.class, "value", "value");

		xs.alias("record-property", MarkedResultProperty.class);
		xs.aliasAttribute(MarkedResultProperty.class, "name", "name");
		xs.aliasAttribute(MarkedResultProperty.class, "value", "value");

		xs.aliasField("marker", MarkedResultProperty.class, "marker");

		highlightXStream(xs);
	}

	public static void highlightXStream(XStream xs) {
		xs.alias("default-marker", KeywordMarker.class);

		xs.aliasField("style", KeywordMarker.class, "style");
		xs.alias("simple-style", SimpleMark.class);
		xs.aliasAttribute(SimpleMark.class, "headFont", "head");
		xs.aliasAttribute(SimpleMark.class, "tailFont", "tail");

		xs.aliasField("mark-strategies", KeywordMarker.class, "strategyList");
		xs.alias("same-mark", SameMarkStrategy.class);
		xs.alias("same-rs-mark", SameRemoveSpecialMarkStrategy.class);
		xs.alias("pinyin-mark", PinyinMarkStrategy.class);
		xs.alias("pinyin-rs-mark", PinYinRMSpecialMarkStrategy.class);
		xs.alias("split-mark", SplitedMarkStrategy.class);
	}

	public static void sorterInformationXStream(XStream xs) {
		xs.alias("sorter-name", SorterInformation.class);
		xs.aliasAttribute(SorterInformation.class, "name", "name");
		xs.aliasAttribute(SorterInformation.class, "used", "isUsed");
	}

	public static void searchStrategyXStream(XStream xs) {
		xs.aliasAttribute(AbstractSearchStrategy.class, "fieldName", "field");
		xs.aliasAttribute(AbstractSearchStrategy.class, "keywordField",
				"keyword-field");

		xs.alias("same-strategy", SameSearchStrategy.class);
		xs.alias("charsame-strategy", CharSameSearchStrategy.class);
		xs.alias("pinyin-strategy", PinyinSearchStrategy.class);
		xs.alias("split-strategy", SplitedSearchStrategy.class);

		xs.alias("fuzzy-strategy", FuzzySearchStrategy.class);
		xs.aliasAttribute(FuzzySearchStrategy.class, "chineseAmbiguity",
				"chinese-ambiguity");
		xs.aliasAttribute(FuzzySearchStrategy.class, "englishAmbiguity",
				"english-ambiguity");

		xs.alias("missword-strategy", MissWordSearchStrategy.class);
		xs.aliasAttribute(MissWordSearchStrategy.class, "min", "min");
		xs.aliasAttribute(MissWordSearchStrategy.class, "minus", "minus");
		xs.aliasField("spliter", MissWordSearchStrategy.class, "spliter");

		xs.alias("prefix-strategy", PrefixSearchStrategy.class);
		xs.alias("suffix-strategy", SuffixSearchStrategy.class);

		spliterXStream(xs);
	}

	public static void spliterXStream(XStream xs) {
		xs.alias("word-spiter", WordSpliter.class);
	}
}
